using Hangfire;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Extensions.Hosting;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using ORS.OrderRobot;
using ORS.OrderRobot.Cache;
using ORS.OrderRobot.Domain.Shared;
using ORS.OrderRobot.EFCore;
using ORS.OrderRobot.Foundation.Hangfire;
using ORS.OrderRobot.IOC;
using ORS.OrderRobot.Queue;
using ORS.OrderRobot.Service;
using ORS.OrderRobot.Service.Tasker;
using ORS.OrderRobot.WebApp.Filter;
using Serilog;
using Serilog.Events;
using StackExchange.Redis;
using System.Text;

public class Program
{
    public static async Task Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .MinimumLevel.Information()  // 设置最低日志级别
            .MinimumLevel.Override("Hangfire", LogEventLevel.Error)// Hangfire 仅输出 Warning 及以上
            .WriteTo.Async(a => a.Console())  // 异步输出日志到控制台
            .WriteTo.Async(a => a.File("logs/log.txt",
                rollingInterval: RollingInterval.Hour,
                buffered: true,
                retainedFileCountLimit: 36,
                fileSizeLimitBytes: 10 * 1024 * 1024))  // 每个日志文件最大10MB
            .CreateLogger();

        var builder = WebApplication.CreateBuilder(args);
        builder.Host.UseSerilog();
        // 读取 appsettings.json 的 WebHost:Urls 配置
        var urls = builder.Configuration["WebHost:Urls"];
        if (!string.IsNullOrWhiteSpace(urls))
        {
            builder.WebHost.UseUrls(urls);
        }
        ConfigureServices(builder.Services, builder.Configuration);

        var app = builder.Build();
        // 启动后打印监听端口号和地址
        app.Lifetime.ApplicationStarted.Register(() =>
        {
            foreach (var address in app.Urls)
            {
                Log.Information($"应用已启动，监听地址: {address}");
            }
        });
        ServiceProviderAccessor.Set(app.Services);
        ConfigureMiddleware(app);
        await app.Services.BackgroundWorkersRegisterAsync();

        #pragma warning disable CS4014
        //Task.Run(async () =>
        //{
        //    using var scope = app.Services.CreateScope();
        //    var loginService = scope.ServiceProvider.GetRequiredService<IAccountLoginService>();
        //    try
        //    {
        //        await loginService.AutoLoginAsync();
        //    }
        //    catch
        //    {
        //    }
        //});
        app.Run();
    }

    private static void ConfigureServices(IServiceCollection services, IConfiguration configuration)
    {
        AddCorsPolicy(services, configuration);
        // 添加 SignalR 服务
        services.AddSignalR();
        #region JwtToken
        var jwtSettings = new JwtSettings();
        configuration.GetSection("JwtSettings").Bind(jwtSettings);
        services.Configure<JwtSettings>(configuration.GetSection("JwtSettings"));
        // 配置JWT认证
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
            .AddJwtBearer(options =>
            {
                options.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwtSettings.SecretKey)),
                    ValidateIssuer = true,
                    ValidIssuer = jwtSettings.Issuer,
                    ValidateAudience = true,
                    ValidAudience = jwtSettings.Audience,
                    ValidateLifetime = true,
                    ClockSkew = TimeSpan.Zero
                };
            });
        services.AddAuthorization();
        #endregion

        services.AddControllers(options =>
        {
            // 将自定义的异常过滤器添加到控制器的过滤器列表,发生异常时自动返回异常对象
            options.Filters.Add<ExceptionFilter>();
        }).AddJsonOptions(options =>
        {
            // 配置自定义日期时间格式化
            options.JsonSerializerOptions.Converters.Add(new JsonDateTimeConverter());
        });
        services.AddEndpointsApiExplorer();
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("api", new OpenApiInfo { Title = "My API", Version = "api" });
            c.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, "ORS.OrderRobot.WebApp.xml")); 
            // 添加JWT认证配置到Swagger
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey,
                Scheme = "Bearer"
            });
            c.AddSecurityRequirement(new OpenApiSecurityRequirement
            {
                {
                    new OpenApiSecurityScheme
                    {
                        Reference = new OpenApiReference
                        {
                            Type = ReferenceType.SecurityScheme,
                            Id = "Bearer"
                        }
                    },
                    Array.Empty<string>()
                }
            });
        });
        services.AddAutoInject();
        services.AddDataLayer(configuration);
        services.AddDtoMappers();
        services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblyContaining<FlightInfoService>());
        services.AddHangfireWorkerManager(configuration);

        var redisOptions = new ConfigurationOptions
        {
            EndPoints = { configuration.GetConnectionString("Redis") ?? "localhost:6379" },
            Password = configuration["Redis:Password"],
            Ssl = configuration.GetValue("Redis:UseSsl", false),
            ConnectTimeout = configuration.GetValue("Redis:ConnectTimeout", 5) * 1000,
            SyncTimeout = configuration.GetValue("Redis:SyncTimeout", 5) * 1000,
            DefaultDatabase = 0
        };

        AddCacheServices(services, configuration, redisOptions);
        AddMessageQueueServices(services, configuration, redisOptions);
        services.AddSingleton<AutoShoppingTasker>();
        services.AddSingleton<IBackgroundRepeatTasker>(sp => sp.GetRequiredService<AutoShoppingTasker>());
        services.AddSingleton<IHostedService>(sp => sp.GetRequiredService<AutoShoppingTasker>());
    }

    private static void ConfigureMiddleware(WebApplication app)
    {
        #region 静态文件
        app.UseDefaultFiles();
        app.UseStaticFiles();
        #endregion

        #region swagger
        app.UseSwagger(c =>
        {
            c.RouteTemplate = "myapi/{documentName}/swagger.json";
        });
        app.UseSwaggerUI(options =>
        {
            options.RoutePrefix = "myapi";
            options.SwaggerEndpoint("/myapi/api/swagger.json", "My API");
        });
        #endregion

        app.UseHttpsRedirection();
        
        #region CORS中间件 - 必须在SignalR之前
        var corsPolicy = app.Services.GetService<IConfiguration>()?["Cors:Origins"];
        if (!string.IsNullOrEmpty(corsPolicy))
        {
            app.UseCors("DefaultCorsPolicy");
        }
        #endregion
        
        // 添加认证和授权中间件
        app.UseAuthentication();
        app.UseAuthorization();
        
        app.MapControllers();
        app.UseHangfireDashboard("/task", new DashboardOptions
        {
            //Authorization = new[] { new MyAuthorizationFilter() }
        });

        #region SignalR中间件
        app.UseRouting();
        app.UseEndpoints(endpoints =>
        {
            // 映射 SignalR Hub
            endpoints.MapHub<MessageHub>("/chat", options =>
            {
                // 允许跨域
                options.Transports = Microsoft.AspNetCore.Http.Connections.HttpTransportType.WebSockets | Microsoft.AspNetCore.Http.Connections.HttpTransportType.LongPolling;
            });
        });
        #endregion
    }

    private static void AddCorsPolicy(IServiceCollection services, IConfiguration configuration)
    {
        var corsOrigins = configuration["Cors:Origins"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        var allowedHeaders = configuration["Cors:AllowedHeaders"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        var allowedMethods = configuration["Cors:AllowedMethods"]?.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
        var allowCredentials = configuration.GetValue("Cors:AllowCredentials", true);

        // 校验：如果AllowCredentials为true且Origins未配置，抛出异常或警告
        if (allowCredentials && (corsOrigins == null || corsOrigins.Length == 0 || string.IsNullOrWhiteSpace(configuration["Cors:Origins"])))
        {
            throw new InvalidOperationException("CORS配置错误：AllowCredentials为true时，必须指定具体的Origins，不能为*或空。");
        }

        services.AddCors(options =>
        {
            options.AddPolicy("DefaultCorsPolicy", builder =>
            {
                // 域名
                if (corsOrigins != null && corsOrigins.Length > 0 && !string.IsNullOrWhiteSpace(configuration["Cors:Origins"]))
                    builder.WithOrigins(corsOrigins).SetIsOriginAllowedToAllowWildcardSubdomains();
                else
                    builder.AllowAnyOrigin();

                // 头
                if (allowedHeaders != null && allowedHeaders.Length > 0 && !string.IsNullOrWhiteSpace(configuration["Cors:AllowedHeaders"]))
                    builder.WithHeaders(allowedHeaders);
                else
                    builder.AllowAnyHeader();

                // 方法
                if (allowedMethods != null && allowedMethods.Length > 0 && !string.IsNullOrWhiteSpace(configuration["Cors:AllowedMethods"]))
                    builder.WithMethods(allowedMethods);
                else
                    builder.AllowAnyMethod();

                if (allowCredentials)
                    builder.AllowCredentials();
            });
        });
    }

    private static void AddCacheServices(IServiceCollection services, IConfiguration configuration, ConfigurationOptions redisOptions)
    {
        if (configuration["Foundation:Cache"] == "Redis")
        {
            services.AddSingleton<IConnectionMultiplexer>(sp => ConnectionMultiplexer.Connect(redisOptions));
            services.AddSingleton<ICache, RedisCache>();
        }
        else
        {
            services.AddMemoryCache();
            services.AddSingleton<ICache, MemoryCache>();
        }
    }

    private static void AddMessageQueueServices(IServiceCollection services, IConfiguration configuration, ConfigurationOptions redisOptions)
    {
        if (configuration["Foundation:MessageQueue"] == "Redis")
        {
            services.AddSingleton<IConnectionMultiplexer>(sp => ConnectionMultiplexer.Connect(redisOptions));
            services.AddSingleton(typeof(IMessageQueue<>), typeof(RedisMessageQueue<>));
        }
        else
        {
            services.AddSingleton(typeof(IMessageQueue<>), typeof(DefaultMessageQueue<>));
        }
    }
}
